package com.fulihui.information.biz.job;

import com.fulihui.information.biz.content.CategoryBizManager;
import com.fulihui.information.common.config.AppConst;
import com.fulihui.information.core.db.ContentCounterDB;
import com.fulihui.information.core.redis.*;
import com.fulihui.information.dto.CategoryDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.near.toolkit.common.StringUtil.EMPTY_STRING;

/**
 * 清除旧的资讯列表内容定时任务
 *
 * @author Willard.Hu on 2017/2/6 0006.
 */
public class ClearRedisOldContentJob     {
    private static final Logger log = LoggerFactory.getLogger(
            com.fulihui.information.util.LoggerNames.CLEAR_REDIS_OLD_CONTENT_JOB_LOGGERNAME);

    // XXX 表结构兼容多产品，目前只支持 YOUKANTOU 应用的清理
    private static final String DEFATUL_PRODUCT_CODE = "YOUKANTOU";

    @Autowired
    private CategoryBizManager                categoryBizManager;
    @Autowired
    private RedisContentCounterDB             redisContentCounterDB;
    @Autowired
    private RedisBasicCategoryContentSortDB   redisBasicCategoryContentSortDB;
    @Autowired
    private RedisHotsContentReadTimesSortDB   redisHotsContentReadTimesSortDB;
    @Autowired
    private RedisHotsContentSharedTimesSortDB redisHotsContentSharedTimesSortDB;
    @Autowired
    private RedisContentListItemDB            redisContentListItemDB;
    @Autowired
    private AppConst                          appConst;


    public void execute(   ) {
        // 读取有效类目
        List<CategoryDTO> categoryList = categoryBizManager.queryGroup(DEFATUL_PRODUCT_CODE, EMPTY_STRING);
        if (log.isDebugEnabled()) {
            log.debug("Category -> {}", categoryList.stream()
                    .map(CategoryDTO::getCode)
                    .collect(Collectors.toList()));
        }
        // 便利类目找出按排序条件大于n条的数据(n为最大保留数据数)
        categoryList.forEach(it -> {
            try {
                log.info("Execute remove '{}' old contents", it.getCode());
                removeCategoryOldContents(it.getCode());
            } catch (Exception e) {
                log.error(it.getCode() + "-" + e.getMessage(), e);
            }
        });
        // 热门单独处理，值删除列表缓存的，其他的不删除
        removeHotsOladContents();
    }

    /**
     * 删除类目下多余数据，并且把在热点、统计数和列表内容的json串的也同时删除
     *
     * @param categoryCode 类目代码
     */
    private void removeCategoryOldContents(String categoryCode) {
        long totalSzie = redisBasicCategoryContentSortDB.size(categoryCode);
        int maxSize = appConst.getContentRedisListItemMaxSize();
        log.info("Total size {}, remove size {}", totalSzie,
                totalSzie > maxSize ? totalSzie - maxSize : 0);
        // 未达到数据上线，无需删除
        if (totalSzie > maxSize) {
            Set<String> ids = redisBasicCategoryContentSortDB.range(maxSize, Integer.MAX_VALUE, categoryCode);
            if (log.isDebugEnabled()) {
                log.debug("Remove contents -> {}", ids);
            }
            ids.forEach(it -> {
                try {
                    removeOldContent(categoryCode, it);
                } catch (Exception e) {
                    // 打印执行失败的资讯id后续手动处理
                    log.error(it + "- remove failed, error: " + e.getMessage(), e);
                }
            });
        }
    }

    /**
     * 删除单条旧的资讯列表内容处理函数(单条处理容易补偿，后续再考虑事务的接入，事务接入后可以批量删除)
     *
     * @param categoryCode 类目代码
     * @param contentId    资讯主键
     */
    private void removeOldContent(String categoryCode, String contentId) {
        // 移除统计数
        for (ContentCounterDB.CounterType counterKey : ContentCounterDB.CounterType.values()) {
            redisContentCounterDB.multiDelete(counterKey, contentId);
        }
        redisBasicCategoryContentSortDB.remove(categoryCode, contentId);
        redisHotsContentReadTimesSortDB.remove(EMPTY_STRING, contentId);
        redisHotsContentSharedTimesSortDB.remove(EMPTY_STRING, contentId);
        redisContentListItemDB.batchDelete(contentId);
    }

    /**
     * 热门单独处理，值删除列表缓存的，其他的不删除
     */
    private void removeHotsOladContents() {
        int maxSize = appConst.getContentRedisListItemMaxSize();
        // 处理按阅读数排序的热门数据
        long hotsReadTimesSize = redisHotsContentReadTimesSortDB.size(null);
        log.info("Execute remove 'YOUKANTOU_ALL_HOTS_READTIMES' old contents");
        log.info("Total size {}, remove size {}", hotsReadTimesSize,
                hotsReadTimesSize > maxSize ? hotsReadTimesSize - maxSize : 0);
        if (hotsReadTimesSize > maxSize) {
            redisHotsContentReadTimesSortDB.removeRange(0,
                    (int) (hotsReadTimesSize - maxSize), null);
        }
        // 处理按分享数排序的热门数据
        long hotsSharedTimesSize = redisHotsContentSharedTimesSortDB.size(null);
        log.info("Execute remove 'YOUKANTOU_ALL_HOTS_SHAREDTIMES' old contents");
        log.info("Total size {}, remove size {}", hotsSharedTimesSize,
                hotsSharedTimesSize > maxSize ? hotsSharedTimesSize - maxSize : 0);
        if (hotsSharedTimesSize > maxSize) {
            redisHotsContentSharedTimesSortDB.removeRange(0,
                    (int) (hotsSharedTimesSize - maxSize), null);
        }
    }
}
